﻿using LiteBlog.Common.Components;
using LiteBlog.Common.Entities;
using LiteBlog.Components.Contracts;
using LiteBlog.Components.Enums;
using LiteBlog.Repositories.Contracts;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Syndication;

namespace LiteBlog.Components
{
    public class FeedComp : IFeedComp
    {
        private ICacheComp _cache;

        public FeedComp(ICacheComp cache,
            ISettingsComp settingsComp,
            IAuthorComp authorComp,
            IBlogRepository blogRepo,
            IPostRepository postRepo,
            ICategoryRepository catRepo)
        {
            _cache = cache;
            _blogRepo = blogRepo;
            _postRepo = postRepo;
            _categoryRepo = catRepo;
            _authorComp = authorComp;
            _settingsComp = settingsComp;
        }

        public SyndicationFeed GetFeed()
        {
            var feed = _cache.Get<SyndicationFeed>(CacheType.Feed);
            if (feed == null)
            {
                feed = GetFeedInternal();
                _cache.Put(CacheType.Feed, feed);
            }
            return feed;
        }

        private SyndicationFeed GetFeedInternal()
        {

            Settings app = SettingsComponent.Load();
            string url = app.Url;
            if (url == string.Empty)
            {
                Uri uri = System.Web.HttpContext.Current.Request.Url;
                string dnsPath = uri.Scheme + "://" + uri.Host;
                if (!uri.IsDefaultPort)
                {
                    dnsPath = dnsPath + ":" + uri.Port.ToString();
                }

                string appPath = System.Web.HttpContext.Current.Request.ApplicationPath;
                url = dnsPath + appPath;
            }

            if (url.Substring(url.Length - 1, 1) != "/")
            {
                url += "/";
            }

            var postInfos = _blogRepo.GetPublished()
                                                    .OrderByDescending(pi => pi.Time)
                                                    .Take(20)
                                                    .ToList();

            List<SyndicationItem> items = new List<SyndicationItem>();

            foreach (PostInfo postInfo in postInfos)
            {
                SyndicationItem item = new SyndicationItem();
                item.Title = SyndicationContent.CreatePlaintextContent(postInfo.Title);

                item.PublishDate = new DateTimeOffset(postInfo.Time, DateTimeHelper.TimezoneOffset);
                item.LastUpdatedTime = new DateTimeOffset(postInfo.UpdatedTime, DateTimeHelper.TimezoneOffset);

                string url2 = string.Format("{0}Post/{1}", url, postInfo.FileID);
                SyndicationLink link = SyndicationLink.CreateAlternateLink(new Uri(url2));

                item.Links.Add(link);

                var post = _postRepo.Load(postInfo.FileID);
                item.Content = SyndicationContent.CreateHtmlContent(post.Contents);

                foreach (var category in post.Categories)
                    item.Categories.Add(new SyndicationCategory(category.Name));

                items.Add(item);
            }

            var feed = new SyndicationFeed(items);

            feed.Title = SyndicationContent.CreatePlaintextContent(app.Name);
            feed.Links.Add(SyndicationLink.CreateAlternateLink(new Uri(url)));

            var authors = AuthorComponent.Get();
            foreach (Author author in authors)
            {
                feed.Authors.Add(new SyndicationPerson(author.Email, author.Name, author.Url));
            }

            var categories = _categoryRepo.Get();
            foreach (var category in categories)
            {
                feed.Categories.Add(new SyndicationCategory(category.Name));
            }

            return feed;
        }

        public IAuthorComp AuthorComponent
        {
            get
            {
                return _authorComp;
            }
        }
        public ISettingsComp SettingsComponent
        {
            get
            {
                return _settingsComp;
            }
        }

        private IBlogRepository _blogRepo;
        private IPostRepository _postRepo;
        private ICategoryRepository _categoryRepo;
        private IAuthorComp _authorComp;
        private ISettingsComp _settingsComp;
    }
}
